package com.wh1200.mybatis

import com.wh1200.kotlin.containsAny
import com.wh1200.mybatis.xmlless.constant.ClassNames
import com.wh1200.mybatis.xmlless.inter.ITypeResolver
import com.wh1200.mybatis.xmlless.resolver.TypeResolver
import com.wh1200.mybatis.xmlless.util.ClassUtils
import com.fasterxml.jackson.databind.JavaType
import org.springframework.core.ResolvableType
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType

/**
 *
 * @author 吴昊
 * @date 2024/1/17 0:02
 * @since v0.0.0
 * @version 1.0
 */
class SpringTypeResolver : ITypeResolver {
  override fun resolveReturnJavaType(method: Method, clazz: Class<*>, forceSingleValue: Boolean): JavaType? {
    val type = if (!forceSingleValue && Collection::class.java.isAssignableFrom(method.returnType)) {
      ResolvableType.forMethodReturnType(method, clazz).generics[0]
    } else {
      ResolvableType.forMethodReturnType(method, clazz)
    }
    if (type.type is ParameterizedType) {
      return TypeResolver.toJavaType(type.type)
    }
    return TypeResolver.toJavaType(type.resolve() ?: type.type)
  }

  override fun resolveReturnMappingType(method: Method, clazz: Class<*>): Class<*>? {
    val interfaces = ClassUtils.getAllClassOrInterface(method.returnType).map { it.name }
    val hasGenericType = interfaces.containsAny(
        listOf(
            ClassNames.JAVA_COLLECTION,
            ClassNames.SPRING_DATA_PAGE,
            ClassNames.MYBATIS_PLUS_PAGE
        )
    )
    return if (hasGenericType) {
      val type = ResolvableType.forMethodReturnType(method, clazz).generics[0].resolve()
      if (type is Class<*>) {
        type
      } else {
        method.returnType
      }
    } else {
      ResolvableType.forMethodReturnType(method, clazz).resolve()
    }
  }
}
